﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App1AppHandler;
using System.Drawing;
using System.Timers;
using Reborn_WorldServer;

namespace Reborn_Server.App1AppHandler
{
    public class Spell_FogOfEnfeeblement : AreaSpell
    {
        public int damageLow = 100;
        public int damageHigh = 150;

        //This spell expands to more tiles sequentially. Expand every 5 rounds for 3 rounds.
        private int expandAtInterval = 4;
        private int maxExpand = 4;
        //Determines the range from the origional point to expand to.
        private int intervalCounter = 0;

        public Spell_FogOfEnfeeblement() 
        {
            DurationLow = 22;
            DurationHigh = 31;
        }

        public void PositionCast(SpellIcon _spellIcon, CreatureBase myCreatureBase, int CastLevel, int MapX, int MapY)
        {
            List<MapItem> MapItemsWithin12;
            base.InitializeInstantCast(myCreatureBase, CastLevel, _spellIcon, MapX, MapY, out MapItemsWithin12);

            damageLow = SkillManager.AdjustForCombat(CastLevel, damageLow, myCreatureBase.IntelligenceTotal);
            damageHigh = SkillManager.AdjustForCombat(CastLevel, damageHigh, myCreatureBase.IntelligenceTotal);

            MainCast(myCreatureBase, CastMapX, CastMapY, MapItemsWithin12);
        }

        private void MainCast(CreatureBase myCreatureBase, int MapX, int MapY, List<MapItem> MapItemsWithin12)
        {
            //List<Point> HiddenList = CreatureAI.FindHidden(CastMapX, CastMapY, MapItemsWithin12);

            List<Character> CharactersWithinUpdateRange = new List<Character>();
            foreach (MapItem mapitem in MapItemsWithin12)
            {
                foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                {
                    if (creatureBase is Character)
                        CharactersWithinUpdateRange.Add((Character)creatureBase);
                }
            }

            //Check if the cast map item is valid. If not, it will cast anyway and will expand to valid map items.
            if (CastMapItem.Motion > 0 && CastMapItem.TerrainType != "Water" && CastMapItem.Transparent == true)
            {
                //Remove any existing instances of the spell from the targeted map item.
                foreach (Spell spell in CastMapItem.SpellLayer1)
                {
                    if (spell.spellIcon.StackType != "" && spell.spellIcon.StackType == this.spellIcon.StackType)
                    {
                        CastMapItem.SpellLayer1.Remove(spell);
                        break;
                    }
                }

                CastMapItem.SpellLayer1.Add(this);
                MapItems.Add(CastMapItem);
            }

            List<CreatureBase> creaturesToDamage = new List<CreatureBase>();
            foreach (MapItem mapitem in MapItems)
            {
                foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                {
                    if (creatureBase.HP < 1)
                        continue;

                    creaturesToDamage.Add(creatureBase);
                }
            }
            foreach (CreatureBase creatureBase in creaturesToDamage)
            {
                if (creatureBase.HP < 1)
                    continue;

                //Get the creature we would give a SD flag to.
                Character characterToApplyFlag = null;

                //If the creature we're casting at is a pet, get its master
                Pet_Controller pc = creatureBase.petController;
                //Has pet controller, check if master is character
                if (pc != null && pc.MasterCreature is Character)
                    characterToApplyFlag = (Character)pc.MasterCreature;
                //No pet controller, check if target is character
                else if (pc == null && creatureBase is Character)
                    characterToApplyFlag = (Character)creatureBase;

                //If we're attacking a player, and we dont have a flag on them, give them a flag on us.
                if (characterToApplyFlag != null &&
                    myCreatureBase is Character &&
                    characterToApplyFlag != myCreatureBase &&
                    myCreatureBase.hateManager.GetCreatureHateInfo(characterToApplyFlag) == null &&
                    spellIcon.Offensive == true)
                {
                    Character charToAttack = (Character)characterToApplyFlag;
                    if (charToAttack.friendsManager.hasNoSDFlag(CastingCharacterID) == false)
                    {
                        if (charToAttack.hateManager.GetCreatureHateInfo(myCreatureBase) == null)
                        {
                            charToAttack.SendMessage("You have been ATTACKED by " + myCreatureBase.Name + "!", "damaged");
                            charToAttack.PlaySound("Ding", charToAttack.MapX, charToAttack.MapY);

                            charToAttack.hateManager.UpdateList(myCreatureBase, 0);

                            charToAttack.AddMapItem(myCreatureBase.currentMapItem);
                        }
                        else
                            charToAttack.hateManager.UpdateList(myCreatureBase, 0);
                    }
                }

                int dmg = Managers.GameHandler.random.Next(damageLow, damageHigh + 1);

                int reducedDamage = creatureBase.CalculateGetSpellDamagePerResists(dmg, this.spellIcon.Skill);
                int absorbedDamage;

                creatureBase.InflictSpellDamage(reducedDamage, CastingCharacterID, CastingCreatureGUID, spellIcon.Skill, out absorbedDamage);
                creatureBase.Stamina = creatureBase.Stamina - reducedDamage;
                creatureBase.Mana = creatureBase.Mana - reducedDamage;

                creatureBase.Update_Character();

                reducedDamage = reducedDamage - absorbedDamage;

                string targetMessageText = "You are withering! (" + reducedDamage.ToString() + ")";
                string casterMessageText = "You wither " + creatureBase.Name + " (" + reducedDamage.ToString() + ")";
                
                if (absorbedDamage != 0 && targetMessageText != "")
                    targetMessageText = targetMessageText + " ABSORBED " + absorbedDamage.ToString();
                if (absorbedDamage != 0 && casterMessageText != "")
                    casterMessageText = casterMessageText + " ABSORBED " + absorbedDamage.ToString();

                if (targetMessageText != "")
                    creatureBase.SendMessage(targetMessageText, "spelldamaged");
                if (casterMessageText != "" && (creatureBase.ID != CastingCharacterID))
                    Managers.GameHandler.TrySendMessage(CastingCharacterID, casterMessageText, "spelldamage");
            }
            foreach (MapItem mapitem in MapItems)
            {
                for (int x = 0; x < mapitem.CreaturesBases.Count; x++)
                {
                    CreatureBase creaturebase = (CreatureBase)mapitem.CreaturesBases[x];

                    if (creaturebase.HP < 1)
                    {
                        if (!(creaturebase is Character))
                        {
                            mapitem.CreaturesBases.RemoveAt(x);
                            x--;
                        }
                    }
                }
            }

            if (MapItems.Count > 0)
            {
                foreach (Character character in CharactersWithinUpdateRange)
                {
                    character.AddMapItems(MapItems, false);

                    if (spellIcon.Skill == "Fire")
                        character.PlaySound("FireBall", CastMapX, CastMapY);
                }
            }

            //Start Spell Timer
            spellTimer.Start();
        }

        protected override void SpellTimer_Expired(object source, ElapsedEventArgs e)
        {
            TimerCounter = TimerCounter + 1;

            //Check if we've hit an interval to expand the area effect
            bool isExpandInterval = TimerCounter % this.expandAtInterval == 0 ? true : false;
            if (isExpandInterval)
                intervalCounter++;

            //If the area effect is at maximum size, dont expand.
            if (intervalCounter > maxExpand)
                isExpandInterval = false;

            //Get MapLock
            LockItem MapLock = Managers.GameHandler.GetLockItem(MapID, Instance);

            //Lock MapLock
            lock (MapLock.LockObj)
            {
                Map CurrentMap = Managers.GameHandler.GetMap(MapID, Instance);

                for (int x = 0; x < MapItems.Count; x++)
                {
                    MapItem mapItem = MapItems[x];
                    if (mapItem.SpellLayer1.Contains(this) == false)
                    {
                        MapItems.RemoveAt(x);
                        x--;
                    }
                }

                //If this spell is done expanding, and there are no map items containing it, stop running
                if (MapItems.Count == 0 && intervalCounter >= 3 && isExpandInterval == false)
                    return;

                //Expand the AOE effect
                List<MapItem> MapItemsToUpdate = new List<MapItem>();
                if (isExpandInterval)
                {
                    List<Point> HiddenList = CreatureAI.FindHidden(CastMapX, CastMapY, CastMapItem.mapItemsWithin4);

                    foreach (MapItem mapitem in CastMapItem.mapItemsWithin8)
                    {
                        if (mapitem.SpellLayer1.Contains(this))
                            continue;

                        //Expand outward, use the interval as the range from the casting point
                        if ((Math.Abs(mapitem.MapX - CastMapX) <= intervalCounter && Math.Abs(mapitem.MapY - CastMapY) <= intervalCounter) &&
                            !(Math.Abs(mapitem.MapX - CastMapX) == intervalCounter && Math.Abs(mapitem.MapY - CastMapY) == intervalCounter) &&
                            CreatureAI.isHidden(mapitem.MapX, mapitem.MapY, HiddenList) == false &&
                            mapitem.Motion > 0 && mapitem.TerrainType != "Water" && mapitem.Transparent == true)
                        {
                            //Remove existing instances of this spell from the map item
                            foreach (Spell spell in mapitem.SpellLayer1)
                            {
                                if (spell.spellIcon.StackType != "" && spell.spellIcon.StackType == spellIcon.StackType)
                                {
                                    mapitem.SpellLayer1.Remove(spell);
                                    break;
                                }
                            }
                            mapitem.SpellLayer1.Add(this);
                            MapItems.Add(mapitem);

                            if (MapItemsToUpdate.Contains(mapitem) == false)
                                MapItemsToUpdate.Add(mapitem);
                        }
                    }
                }

                //Remove the effect from appropriate tiles
                foreach (MapItem mapitem in MapItems)
                {
                    if (mapitem.SpellLayer1.Contains(this) == false)
                        continue;

                    if (TimerCounter >= DurationLow)
                    {
                        if (mapitem.MapX != CastMapX || mapitem.MapY != CastMapY)
                        {
                            int RemoveSpell = Managers.GameHandler.random.Next(-1, DurationHigh - TimerCounter);
                            if (RemoveSpell == -1)
                            {
                                mapitem.SpellLayer1.Remove(this);

                                if (MapItemsToUpdate.Contains(mapitem) == false)
                                    MapItemsToUpdate.Add(mapitem);

                                continue;
                            }
                        }
                        else if (TimerCounter >= DurationHigh)
                        {
                            mapitem.SpellLayer1.Remove(this);

                            if (MapItemsToUpdate.Contains(mapitem) == false)
                                MapItemsToUpdate.Add(mapitem);

                            continue;
                        }
                    }
                }

                List<Character> CharsToUpdate = new List<Character>();
                //Send Updated Hexes to all characters within 8 of any hex effected
                foreach (MapItem mapitem in CastMapItem.mapItemsWithin12)
                {
                    foreach (MapItem mitem in MapItems)
                    {
                        if (Math.Abs(mitem.MapX - mapitem.MapX) <= 8 && Math.Abs(mitem.MapY - mapitem.MapY) <= 8)
                        {
                            foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                            {
                                if (creatureBase is Character)
                                    CharsToUpdate.Add((Character)creatureBase);
                            }
                            break;
                        }
                    }
                }

                List<CreatureBase> creaturesToDamage = new List<CreatureBase>();
                foreach (MapItem mapitem in MapItems)
                {
                    foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                    {
                        if (creatureBase.HP > 1)
                            creaturesToDamage.Add(creatureBase);
                    }
                }

                foreach (CreatureBase creatureBase in creaturesToDamage)
                {
                    int dmg = Managers.GameHandler.random.Next(damageLow, damageHigh + 1);

                    int reducedDamage = creatureBase.CalculateGetSpellDamagePerResists(dmg, this.spellIcon.Skill);
                    int absorbedDamage;

                    creatureBase.InflictSpellDamage(reducedDamage, CastingCharacterID, CastingCreatureGUID, spellIcon.Skill, out absorbedDamage);
                    creatureBase.Stamina = creatureBase.Stamina - reducedDamage;
                    creatureBase.Mana = creatureBase.Mana - reducedDamage;

                    creatureBase.Update_Character();

                    if (MapItemsToUpdate.Contains(creatureBase.currentMapItem) == false)
                        MapItemsToUpdate.Add(creatureBase.currentMapItem);

                    reducedDamage = reducedDamage - absorbedDamage;

                    string targetMessageText = "You are withering! (" + reducedDamage.ToString() + ")";
                    string casterMessageText = "You wither " + creatureBase.Name + " (" + reducedDamage.ToString() + ")";

                    if (absorbedDamage != 0 && targetMessageText != "")
                        targetMessageText = targetMessageText + " ABSORBED " + absorbedDamage.ToString();
                    if (absorbedDamage != 0 && casterMessageText != "")
                        casterMessageText = casterMessageText + " ABSORBED " + absorbedDamage.ToString();

                    if (targetMessageText != "")
                        creatureBase.SendMessage(targetMessageText, "spelldamaged");
                    if (casterMessageText != "" && (creatureBase.ID != CastingCharacterID))
                        Managers.GameHandler.TrySendMessage(CastingCharacterID, casterMessageText, "spelldamage");
                }

                foreach (MapItem mapitem in MapItemsToUpdate)
                {
                    //Remove Creatures
                    bool Complete = false;
                    while (Complete == false)
                    {
                        int count = 0;
                        if (mapitem.CreaturesBases.Count == 0)
                            Complete = true;
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            count = count + 1;
                            if (creatureBase.HP < 1 && !(creatureBase is Character))
                            {
                                mapitem.CreaturesBases.Remove(creatureBase);
                                break;
                            }
                            if (count == mapitem.CreaturesBases.Count)
                            {
                                Complete = true;
                            }
                        }
                    }
                }
                foreach (Character character in CharsToUpdate)
                {
                    character.AddMapItems(MapItemsToUpdate, false);
                }
            }
            spellTimer.Start();
        }


    }
}
